#  Copyright 2012 Eric Lawrey, Australian Institute of Marine Science
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.


# Test the function of the columnSubstitute.
columnSubstitute.test <- function() {

	exampleTemplateTable <- data.frame(x = c("g", "", "", "o", 
        "", "", "go"), y = c("d", "b", "good", "oo", "e", "f", 
        "od"), blanks = "", pattern = c("{x}oo{y}", "good", "{y}", 
        "{?g{x}o?}d{? g{y}d?}", "{good} good", "{?no variable?}", 
        "{?{x}{y}?}"), expected = c("good", "good", "good", "good good", 
        "{good} good", "{?no variable?}", "good"), stringsAsFactors = FALSE)
    return(columnSubstitute(exampleTemplateTable))
}

######################################
#    SUBSTITUTE ACROSS COLUMNS       #
######################################
# Resolve the substitutions within the templateTable. This is to handle one
# column referencing another column.
columnSubstitute <- function(templateTable) {

	for (i in 1:ncol(templateTable)) {
		# Perform a quick grep to find any potential variables
		rowsWithSubs <- grep("\\{",templateTable[,i])
		if (length(rowsWithSubs) == 0) {
			next
		}
		
		# ==================================
		# Process conditional substitutions.
		# ==================================
		#{storeName}{? sometext {condAttr1} moretext ?} test {?({condAttr2})?}
		# condAttr1: ''
		# condAttr2:''
		# result: '{storeName} test'
		#
		# condAttr1: 'abc'
		# condAttr2:'123'
		# result: '{storeName} sometext abc moretext test (123)'
		for (rw in 1:nrow(templateTable)) {
			cellString <- templateTable[rw, i]
			condMatches <- gregexpr("\\{\\?.*?\\?\\}", cellString)

			if (any(condMatches[[1]] == -1)) {
				next
			}
			condSubs <- regmatches(cellString, condMatches)[[1]]
			literalText <- regmatches(cellString, condMatches, invert=TRUE)[[1]]

			
			processedCondSubs <- c()
			# Process each condition substitution
			
			for (condInd in 1: length(condSubs)) {
				condSub <- condSubs[condInd]
			
				# Find all the variables within each of the conditional substitution statements
				# Only use the first for checking the state of the condition statement
				attrib <- regmatches(condSub, regexpr("\\{[^\\?].*?\\}", condSub))[1]
				
				trimIn <- function(x, n){
					substr(x, n+1, nchar(x)-n)
				}

				# Find the attribute references that match column names
				# also convert column names to  R variable names
				filteredAttrib <- make.names(trimIn(attrib,1))
			

				# Find the columns in the templateTable matching the filteredAttrib
				attribCol <- which(filteredAttrib==colnames(templateTable))
				if (any(attribCol)) {
					# Look up the value of the variable. If it is blank remove the
					# entire string for the conditional substitution
					attribValue <- templateTable[rw, filteredAttrib]
					if (attribValue=="") {
						processedCondSub <- ""
					} else {
						# Remove the outter {? ?} chars, but leave any attribute column names
						# as these will be replaced later
						# {?123{foo}456?} -> 123{foo}456 if {foo} is not ""
						
						processedCondSub <- trimIn(condSub, 2)
					}
				} else {
					# If no match found for the attribute, don't perform any substitution
					# Don't even remove the outter {? ?}
					warning(paste("columnSubstitute: No match found for:",filteredAttrib, "in",condSub))
					processedCondSub <- condSub
				}
				processedCondSubs[condInd] <- processedCondSub
			}
			
			# Place the non condsub strings in between the processedCondSubs
			# A {?{B}?} C {?{D}E?}{F}
			# if B and D are not "" then
			# c('A ','{B}',' C ','{D}E','{F}')
			outSplitCell <- c()
			outSplitCell[seq(1,(length(literalText)-1)*2+1,2)] <- literalText
			outSplitCell[seq(2,(length(processedCondSubs)-1)*2+2,2)] <- processedCondSubs
			# Paste the string back together with the conditional substitutions removed and processed.
			# Save back into the table.
			templateTable[rw, i] <- paste(outSplitCell, collapse="")
		}
		rowStrings <- templateTable[rowsWithSubs,i]
		
		
		# ======================================
		# Process column variable substitutions.
		# ======================================
		listMatches <- gregexpr("\\{.*?\\}", rowStrings)		# List of vectors
		
		# Perform all the substitutions row by row
		for (rw in 1:length(listMatches)) {
			rowIndex <- rowsWithSubs[rw]
			rowMatches <- listMatches[[rw]]	# Vector of matches, with "match.length" attribute
			origRowString <- rowStrings[rw]
			rowString <- origRowString

			for (k in 1:length(rowMatches)) {
				startPos <- rowMatches[k]
				match.length <- attr(rowMatches,"match.length")[k]
				stopPos <- rowMatches[k]+match.length-1
				attrib <- substr(origRowString, startPos+1, stopPos-1)
				
				# The name of columns are renamed by R to ensure that they are
				# value variable names and so "-" and " " are placed with "."
				filteredAttrib <- make.names(attrib)
				#filteredAttrib <- gsub("[- ]",".", attrib)
				# Go find the value of the attrib
				replaceVal <- templateTable[rowIndex, filteredAttrib]
				
				# Sometimes columns are not yet defined because that will be imported
				# from a table join.
				if (is.null(replaceVal)) {
				#	stop(paste("Could not find column matching for ",
				#		substr(origRowString, startPos, stopPos), " row: ", rowIndex, 
				#			" col: ",i, ". Looked for ",filteredAttrib, sep=""))            
				} else {
	  
					# Progressively replace all the matches. Not the most efficient technique
					# since we use gsub which performs the searching again, but it works.
					rowString <- gsub(paste("\\{",attrib,"\\}",sep=""), replaceVal, rowString)
				}
			}
			templateTable[rowIndex, i] <- rowString

		}
	}
	return(templateTable)
}
